#include <iostream>
#include <unistd.h>
#include <cassert>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstring>
#define MAX 1024
using namespace std;
//a. 管道的4钟情况
//  1.如果管道没有数据了， 读端必须等待，直到有数据为止(写端写入数据了) 。
//  2.如果管道被写满了，写端必须等待，直到有空间为止(读端读走数据)
//  3.写端关闭，读端一直读取,读端回读到read返回值为0， 表示读到文件结尾
//  4.读端关闭，写端一直写， OS会直接杀掉写端进程，通过向目标进程发送SIGPIPE(13)信号，终止目标进程
//b. 管道的5钟特性
//  1.匿名管道， 可以允许具有血缘关系的进程之间进行进程间通信，常用于父子，仅限于此
//  2.匿名管道，默认给读写端要提供同步机制
//  3.面向字节流的 ----了解现象就行 
//  4.管道的生命周期是随进程的 
//  5.管道是单向通信的，半双工通信的一种特殊情况 

int main()
{
    //第一步建立管道
    int pipefd[2] = {0};
    int n = pipe(pipefd);
    assert(n == 0);
    (void*)n;
    cout << "pipefd[0]" << pipefd[0] << ","  << "pipefd[1]" << pipefd[1] << endl; 

    //第二步 创建子进程
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return 1;
    }

    //子写， 父读
    //第三步，父子各自关闭不需要的fd，形成单向通信的管道
    if(id == 0)
    {
        
        //child
        //TODO
        close(pipefd[0]);
        //w - 只向管道写入，没有打印
        //子进程使用
        int cnt = 10;
        while(cnt)
        {
            char message[MAX]; 
            snprintf(message, sizeof(message), "hello father, iam child, pid: %d, cnt: %d", getpid(), cnt);
            cnt --;
            write(pipefd[1], message, strlen(message));

            cout << "write...." << endl;
        }
        cout << "child close w point" << endl;
        close(pipefd[1]);
        exit(0);
    }
    //父进程
    close(pipefd[1]);
    //父进程使用
    char buffer[MAX];
    while(true)
    {
        ssize_t n = read(pipefd[0], buffer, sizeof(buffer) - 1);
        if(n > 0)
        {
            buffer[n] = 0; // 字符串的后面加上"\0"
            cout  << getpid() << "," << "child say:" << buffer << "to me!" << endl; 
        }
        else if (n == 0)
        {
            cout << "child quit , me too!" << endl;
        }
        cout << "father return val(n):" << n << endl;
    }
    int status = 0;
    pid_t rid = waitpid(id, &status, 0);
    if(rid == id)
    {
        cout << "wait success, child exit sig" << (status & 0x7f  )<<  endl;
    }
    return 0;
}